﻿using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using GiveAQuiz.Data;
using GiveAQuiz.Web.Helpers;
using GiveAQuiz.Web.Membership;
using GiveAQuiz.Web.Models;
using System.Web;
using GiveAQuizSite.Services;

namespace GiveAQuizSite.Controllers
{
  /// <summary>
  ///  This class serves as a Controller for actions dealing 
  /// with Quiz management.
  /// </summary>
  public class QuizController : BaseController
  {
    /// <summary>
    /// Creates an instance of QuizController
    /// </summary>
    /// <param name="repository">The IQuizRepository, which stores the
    /// data associated with quizzes.</param>
    /// <param name="membershipSvc">The IMembershipService, which provides
    /// information associated with Users.</param>
    public QuizController(IQuizRepository repository, IMembershipService membershipSvc)
      : base(repository)
    {
      MembershipService = membershipSvc;
    }

    public IMembershipService MembershipService
    {
      get;
      private set;
    }

    private MembershipUser CurrentUser
    {
      get { return MembershipService.CurrentUser; }
    }

    /// <summary>
    /// ~/Quiz
    /// </summary>
    /// <returns>~/Views/Quiz/Index.aspx</returns>
    [Authorize]
    public ActionResult Index()
    {
      Response.Cache.SetCacheability(HttpCacheability.NoCache);
      return View(Repository.GetUserQuizDefinitions((Guid)CurrentUser.ProviderUserKey));
    }

    /// <summary>
    /// ~/Quiz/Pick
    /// </summary>
    /// <returns>~/Views/Quiz/Pick.aspx</returns>
    public ActionResult Pick(string passcode = "")
    {
      var model = new QuizPickerViewModel() { QuizPassphrase = passcode };
      return View(model);
    }

    /// <summary>
    /// ~/Quiz/Pick
    /// </summary>
    /// <param name="model">The form parameters bound to a 
    /// QuizPickerViewModel.</param>
    /// <returns>~/Views/Quiz/Take.aspx</returns>
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Pick(QuizPickerViewModel model)
    {
      // calls QuizPickerValidator
      if (!ModelState.IsValid)
      {
        return View(model);
      }

      // should already by validated by this point that it exists
      var quiz = Repository.GetQuizByPassphrase(model.QuizPassphrase);

      // Pass the info to the take model so we can put it in the Silverlight control
      return RedirectToAction("Take", new { quizId = quiz.Id, name = model.TakerName ?? "Anonymous", email = model.EMail ?? "None", lastVisit = DateTime.Now});
    }

    /// <summary>
    /// ~/Quiz/Take
    /// </summary>
    /// <returns>~/Views/Quiz/Take.aspx</returns>
    public ActionResult Take(TakeQuizViewModel model)
    {
      return View(model);
    }

    /// <summary>
    /// ~/Quiz/Give
    /// </summary>
    /// <returns>~/Views/Quiz/Give.aspx</returns>
    [Authorize]
    public ActionResult Give()
    {
      return RedirectToAction("Index");
    }

    /// <summary>
    /// ~/Quiz/Edit/5
    /// </summary>
    /// <param name="id">The ID of the quiz definition to edit.</param>
    /// <returns>~/Views/Quiz/Create.aspx</returns>
    [Authorize]
    public ActionResult Edit(int id)
    {
      return RedirectToAction("Create", new { id = id.ToString() });
    }

    /// <summary>
    /// ~/Quiz/End/5
    /// </summary>
    /// <param name="id">The Quiz ID to end.</param>
    /// <returns>~/Views/Quiz/Index.aspx</returns>
    [AcceptVerbs(HttpVerbs.Post)]
    [Authorize]
    public ActionResult End(int id)
    {
      try
      {
        // try to find the quiz by ID
        var quiz = Repository.GetQuiz(id);
        quiz.EndDate = DateTime.Now;
        quiz.HasEnded = true;
        Repository.UpdateQuiz(quiz);

        this.FlashMessage(String.Format("The quiz named '{0}' has been ended", quiz.Name));
      }
      catch
      {
        this.AddErrorMessage("The quiz you requested to end was not found");
      }

      return RedirectToAction("Index");
    }

    /// <summary>
    /// ~/Quiz/DeleteDefinition/5
    /// </summary>
    /// <param name="id">The id of the quiz defintion to delete.</param>
    /// <returns>~/Views/Quiz/Index.aspx</returns>
    [Authorize]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult DeleteDefinition(int id)
    {
      try
      {
        // try to find the quiz by ID
        var quizDef = Repository.GetQuizDefintion(id);

        // delete the quiz
        Repository.DeleteQuizDefinition(id);

        this.FlashMessage(String.Format("The quiz definition named '{0}' has been deleted", quizDef.QuizName));
      }
      catch
      {
        this.AddErrorMessage("The quiz definition you requested to delete was not found");
      }

      // reload the current quizzes for this user
      return RedirectToAction("Index");
    }

    /// <summary>
    /// ~/Quiz/Delete/5
    /// </summary>
    /// <param name="id">The id of the quiz to delete.</param>
    /// <returns>~/Views/Quiz/Index.aspx</returns>
    [Authorize]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Delete(int id)
    {
      try
      {
        // try to find the quiz by ID
        var quiz = Repository.GetQuiz(id);

        // delete the quiz
        Repository.DeleteQuiz(id);

        this.FlashMessage(String.Format("The quiz named '{0}' has been deleted", quiz.Name));  
      }
      catch
      {
        this.AddErrorMessage("The quiz you requested to delete was not found");
      }

      // reload the current quizzes for this user
      return RedirectToAction("Index");
    }

    /// <summary>
    /// ~/Quiz/Create/5
    /// </summary>
    /// <param name="id">The ID of the quiz (optional - only applies to edits)</param>
    /// <returns>~/Views/Quiz/Create.aspx</returns>
    [Authorize]
    public ActionResult Create(string id)
    {
      if (string.IsNullOrEmpty(id))
      {
        id = "new";
      }
      this.ViewData["id"] = id;

      return View();
    }    

    /// <summary>
    /// ~/Quiz/Results/5
    /// </summary>
    /// <param name="id">The ID of the quiz for which to retrieve
    /// results.</param>
    /// <returns>~/Views/Quiz/Results.aspx</returns>
    public ActionResult Results(int id)
    {
      var quiz = Repository.GetQuiz(id);

      var owner = quiz.QuizDefinition.QuizUser;

      var model =
        new QuizResultsViewModel
          {
            QuizName = quiz.QuizDefinition.QuizName,
            Owner = String.Format("{0} {1}", owner.FirstName, owner.LastName),
            Results =
              quiz.QuizResults
                .Select(qr =>
                          {
                            var answers = qr.QuizAnswers;
                            return new QuizResultViewModel
                                     {
                                       QuizResultId = qr.Id,
                                       Student = qr.QuizTaker.Name,
                                       CorrectAnswers = 0
                                     };
                          })
              .ToArray()
          };
      return View(model);
    }

    /// <summary>
    /// ~/Quiz/Results/5
    /// </summary>
    /// <param name="id">The ID of the quiz for which to retrieve
    /// results.</param>
    /// <returns>~/Views/Quiz/Results.aspx</returns>
    public ActionResult Details(int id)
    {
      var qr = Repository.GetQuizResult(id);

      var model =
        new QuizDetailsViewModel
          {
            QuizName = qr.Quiz.QuizDefinition.QuizName,
            TakerName = qr.QuizTaker.Name,
            Questions =
              qr.QuizAnswers.Select(qa =>
                                    new QuestionViewModel
                                      {
                                        Text = qa.QuestionDefinition.QuestionText,
                                        Answer = qa.QuestionDefinition.GetAnswerResult(qa.AnswerData),
                                        CorrectAnswer = "" // qa.QuestionDefinition.CorrectAnswer
                                      }).ToArray()
          };
      return View(model);
    }

    /// <summary>
    /// ~/Quiz/Start/5
    /// </summary>
    /// <param name="id">The Quiz ID.</param>
    /// <param name="quizDefinitionId">The QuizDefinition ID.</param>
    /// <returns>~/Views/Quiz/Start.aspx</returns>
    [Authorize]
    public ActionResult Start(int? id, int? quizDefinitionId)
    {
      if ( id.HasValue && id.Value > 0 )
      {
        try
        {
          var quiz = Repository.GetQuiz(id.Value);

          var model =
            new StartQuizViewModel
              {
                QuizId = quiz.Id,
                QuizName = quiz.Name,
                QuizDefinitionId = quiz.QuizDefinitionID,
                Passphrase = quiz.Password,
                StartDate = quiz.StartDate,
                EndDate = quiz.EndDate
              };
          return View(model);
        }
        catch
        {
          this.AddErrorMessage("The quiz you requested to restart not found");
          return RedirectToAction("Index");
        }
      }
      if ( quizDefinitionId.HasValue && quizDefinitionId.Value > 0 )
      {
        return View(new StartQuizViewModel { QuizDefinitionId = quizDefinitionId.Value });  
      }
      
      this.AddErrorMessage("You must select a valid quiz to start");
      return RedirectToAction("Index");
    }

    /// <summary>
    /// ~/Quiz/Start
    /// </summary>
    /// <param name="model">The form parameters bound to a 
    /// StartQuizViewModel object.</param>
    /// <returns>~/Views/Quiz/Index.aspx</returns>
    [Authorize]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Start(StartQuizViewModel model)
    {
      // calls StartQuizValidator
      if ( !ModelState.IsValid)
      {
        return View("Start", model);
      }

      // update or new?
      if ( model.QuizId > 0 )
      {
        try
        {
          var quiz = Repository.GetQuiz(model.QuizId);

          quiz.Name = model.QuizName;
          quiz.Password = model.Passphrase;
          quiz.StartDate = model.StartDate;
          quiz.EndDate = model.EndDate;
          quiz.HasEnded = false;

          Repository.UpdateQuiz(quiz);

          this.FlashMessage(String.Format("The quiz named '{0}' has been update", quiz.Name));
        }
        catch
        {
          this.AddErrorMessage("The quiz you requested to restart was not found");
        }
      }
      else
      {
        var quiz = new Quiz
                      {
                        QuizDefinitionID = model.QuizDefinitionId,
                        Name = model.QuizName,
                        Password = model.Passphrase,
                        StartDate = model.StartDate,
                        EndDate = model.EndDate,
                        IsNameOptional = false,
                        HasEnded = false
                      };

        Repository.SaveQuiz(quiz);

        this.FlashMessage(String.Format("The quiz named '{0}' has been created", quiz.Name));
      }

      return RedirectToAction("Index");
    }

    /// <summary>
    /// ~/Quiz/ClearResults/5
    /// </summary>
    /// <param name="id">The Quiz ID.</param>
    /// <returns>~/Views/Quiz/Index.aspx</returns>
    [Authorize]
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult ClearResults(int id)
    {
      try
      {
        var quiz = Repository.GetQuiz(id);

        Repository.DeleteQuizResults(quiz.Id);

        this.FlashMessage(String.Format("The results have been cleared for the quiz named '{0}'", quiz.Name));
      }
      catch
      {
        this.AddErrorMessage("The quiz you requested to clear results for was not found");
      }

      return this.RedirectToAction("Index");
    }

   
  }
}
